# 文件名: app/services/api_service.py
import os
import json
import aiohttp
import aiofiles
from dotenv import load_dotenv
import asyncio
import random

from app.utils.logging_config import logger
from app.models.database import SystemSetting, SessionLocal, get_db

# 加载环境变量
load_dotenv()


class ApiService:
    def __init__(self, db=None):
        self.db = db
        # 先使用默认值初始化API令牌
        default_token = os.getenv("API_TOKEN", "")
        self.token = default_token
        # 如果数据库会话为空，尝试创建一个新的会话
        if db is None:
            try:
                self.db = SessionLocal()
                logger.info("在ApiService中创建了新的数据库会话")
            except Exception as e:
                logger.warn(f"在ApiService创建数据库会话时出错: {str(e)}")

        # 尝试从数据库获取令牌
        try:
            if self.db:
                db_token = SystemSetting.get_value(self.db, "api_token", default_token)
                if db_token:
                    self.token = db_token
                    logger.info(f"从数据库加载了API令牌: {self.token[:5]}...")
                else:
                    logger.info(f"使用默认API令牌: {self.token[:5]}...")
        except Exception as e:
            logger.warn(f"获取API令牌时出错: {str(e)}，使用默认值")

        self.headers = {
            'accept': 'application/json',
            'Authorization': f'Bearer {self.token}'
        }

    def update_token(self, new_token=None):
        """更新API令牌，如果未提供则从数据库重新获取"""
        try:
            if new_token:
                self.token = new_token
            elif self.db:
                default_token = os.getenv("API_TOKEN", "")
                db_token = SystemSetting.get_value(self.db, "api_token", default_token)
                if db_token:
                    self.token = db_token

            # 更新请求头
            self.headers = {
                'accept': 'application/json',
                'Authorization': f'Bearer {self.token}'
            }
            logger.info(f"API令牌已更新: {self.token[:5]}...")
        except Exception as e:
            logger.warn(f"更新API令牌时出错: {str(e)}")

    async def random_delay(self, min_delay, max_delay):
        """添加随机延迟"""
        delay = random.uniform(min_delay, max_delay)
        logger.info(f"添加随机延迟: {delay:.2f}秒")
        await asyncio.sleep(delay)

    async def get_platform_delay(self, platform, type_):
        """获取特定平台和操作类型的延迟设置"""
        if self.db is None:
            # 默认延迟
            return 2 if type_ == "user" else 3

        try:
            key = f"{platform}_{type_}_delay"
            delay = float(SystemSetting.get_value(self.db, key, "2"))
            return delay
        except:
            # 出错时使用默认值
            return 2 if type_ == "user" else 3

    # TikTok API 调用
    async def get_tiktok_user(self, username):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("tiktok", "user")
        await self.random_delay(delay * 0.8, delay * 1.2)  # 随机化延迟时间

        url = f"https://api.tikhub.io/api/v1/tiktok/app/v3/handler_user_profile?unique_id={username}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"tiktokAPI响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"tiktokAPI调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"tiktokAPI调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"tiktokAPI连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"tiktokAPI连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"tiktokAPI调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    async def get_tiktok_videos(self, sec_uid, max_cursor=0, count=20, sort_type=0):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("tiktok", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)  # 随机化延迟时间

        """获取TikTok用户视频列表"""
        url = f"https://api.tikhub.io/api/v1/tiktok/app/v3/fetch_user_post_videos?sec_user_id={sec_uid}&max_cursor={max_cursor}&count={count}&sort_type={sort_type}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"tiktokAPI响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"tiktokAPI调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"tiktokAPI调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"tiktokAPI连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"tiktokAPI连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"tiktokAPI调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    # 添加到 ApiService 类中
    async def get_tiktok_single_video(self, aweme_id):
        """获取抖音单个视频详情（高清）"""
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("tiktok", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/tiktok/app/v3/fetch_one_video?aweme_id={aweme_id}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"tiktokAPI响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"tiktokAPI调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"tiktokAPI调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"tiktokAPI连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"tiktokAPI连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"tiktokAPI调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    # 抖音 API 调用
    async def get_douyin_user(self, sec_uid):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        delay = await self.get_platform_delay("douyin", "user")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/douyin/app/v3/handler_user_profile?sec_user_id={sec_uid}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"抖音API响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"抖音API调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音API调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"抖音API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音API连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"抖音API调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    async def get_douyin_videos(self, sec_uid, max_cursor=0, count=20):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("douyin", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/douyin/app/v3/fetch_user_post_videos?sec_user_id={sec_uid}&max_cursor={max_cursor}&count={count}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"抖音API响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"抖音API调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音API调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"抖音API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音API连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"抖音API调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    # 添加到 ApiService 类中
    async def get_douyin_single_video(self, aweme_id):
        """获取抖音单个视频详情（高清）"""
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("douyin", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/douyin/web/fetch_one_video?aweme_id={aweme_id}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"抖音API响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"抖音API调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音API调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"抖音API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音API连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"抖音API调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    async def get_douyin_hot_videos(self, page=1, page_size=10, date_window=24, tags=None):
        """获取抖音热门视频列表"""
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("douyin", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = "https://api.tikhub.io/api/v1/douyin/billboard/fetch_hot_total_video_list"

        # 准备请求体
        payload = {
            "page": page,
            "page_size": page_size,
            "date_window": date_window,
            "tags": tags or [{}]
        }

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.post(
                            url,
                            headers=self.headers,
                            json=payload,
                            timeout=timeout
                    ) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"抖音热门视频API响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"抖音热门视频API调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音热门视频API调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"抖音热门视频API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"抖音热门视频API连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"抖音热门视频API调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    # Instagram API 调用
    async def get_instagram_user(self, username):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("instagram", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/instagram/web_app/fetch_user_info_by_username_v2?username={username}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"instagramAPI响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"instagramAPI调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"instagramAPI调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"instagramAPI连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"instagramAPI连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"instagramAPI调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    async def get_instagram_videos(self, user_id, count=12, max_id=None):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("instagram", "user")
        await self.random_delay(delay * 0.8, delay * 1.2)

        if max_id is None:
            url = f"https://api.tikhub.io/api/v1/instagram/web_app/fetch_user_reels_by_user_id?user_id={user_id}&count={count}"
        else:
            url = f"https://api.tikhub.io/api/v1/instagram/web_app/fetch_user_reels_by_user_id?user_id={user_id}&count={count}&max_id={max_id}"

        print(url)

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"instagramAPI响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(
                    f"instagramAPI调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"instagramAPI调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"instagramAPI连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"instagramAPI连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"instagramAPI调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    # 在 ApiService 类中添加
    async def get_instagram_single_video(self, post_id):
        """获取instagram单个视频详情（高清）"""
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("instagram", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/instagram/web_app/fetch_post_info_by_post_id?post_id={post_id}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"instagramAPI响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"instagramAPI调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"instagramAPI调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"instagramAPI连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"instagramAPI连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"instagramAPI调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    async def get_kuaishou_user(self, user_id):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("kuaishou", "video")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/kuaishou/app/fetch_one_user_v2?user_id={user_id}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"快手API响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(f"快手API调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"快手API调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"快手API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"快手API连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"快手API调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}

    async def get_kuaishou_videos(self, user_id, pcursor=None):
        # 确保令牌正确设置
        if not self.token or self.token.strip() == "":
            self.update_token()

        # 添加延迟
        delay = await self.get_platform_delay("kuaishou", "user")
        await self.random_delay(delay * 0.8, delay * 1.2)

        url = f"https://api.tikhub.io/api/v1/kuaishou/app/fetch_user_post_v2?user_id={user_id}&pcursor={pcursor}"

        # 从系统设置中获取超时和重试次数
        from app.models.database import SystemSetting
        db = next(get_db())
        try:
            timeout_str = SystemSetting.get_value(db, "request_timeout", "180")
            timeout = int(timeout_str)
            max_retries_str = SystemSetting.get_value(db, "max_retries", "3")
            max_retries = int(max_retries_str)
        except Exception as e:
            logger.warning(f"获取超时设置失败，使用默认值: {str(e)}")
            timeout = 180
            max_retries = 3
        finally:
            db.close()

        # 重试逻辑
        for attempt in range(max_retries):
            try:
                async with aiohttp.ClientSession() as session:
                    # 增加超时设置
                    async with session.get(url, headers=self.headers, timeout=timeout) as response:
                        if response.status == 200:
                            data = await response.json()
                            return data
                        else:
                            error_text = await response.text()
                            logger.error(
                                f"快手API响应错误 (尝试 {attempt + 1}/{max_retries}): 状态码 {response.status}, 内容: {error_text[:100]}")
                            if attempt == max_retries - 1:
                                return {"code": response.status, "message": "API请求失败", "data": None}
            except asyncio.TimeoutError:
                wait_time = min(2 ** attempt, 10)  # 指数退避，最长等待10秒
                logger.warning(
                    f"快手API调用超时 (尝试 {attempt + 1}/{max_retries}): 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"快手API调用超时，达到最大重试次数 {max_retries}")
                    return {"code": 408, "message": "API请求超时", "data": None}
                await asyncio.sleep(wait_time)
            except (aiohttp.ClientConnectorError, ConnectionResetError) as e:
                wait_time = min(2 ** attempt, 20)
                logger.warning(
                    f"快手API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}, 等待 {wait_time} 秒后重试")
                if attempt == max_retries - 1:
                    logger.error(f"快手API连接错误，达到最大重试次数 {max_retries}: {str(e)}")
                    return {"code": 502, "message": f"API连接失败: {str(e)}", "data": None}
                await asyncio.sleep(wait_time)
            except Exception as e:
                logger.error(f"快手API调用未知错误: {str(e)}")
                return {"code": 500, "message": f"API调用异常: {str(e)}", "data": None}
